﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

/// <summary>
/// Estrutura que cabeça das animacoes
/// </summary>
public struct Animation
{
    public int width;              // Largura da imagem
    public int height;             // Altura da imagem
    public int frames;             // Quantidade de imagens
    public int fps;                // Quantidade de imagens por segundo
    public int Y;                  // Linha da spritesheet
    public string name;            // Nome da animação
}

namespace SoulKeeper
{
  /// <summary>
  /// Todos os sprites herdam desta classe.
  /// Ela contém os métodos default para update e draw.
  /// Cuida também das animações existentes nos objetos que herdam de sprite.
  /// Essa classe contem em sua maioria mais variaveis do que metodos.
  /// </summary>
   public abstract  class Sprite
    {
        protected GameWindow Window;
        protected Texture2D texture;           //Textura

        protected Vector2 lastPosition;            //Posição atual
        protected Vector2 position;            //Posição atual
        protected Rectangle boundingBox;       //Retângulo de colisão
        protected Vector2 velocity;            //Velocidade atual nos eixos
        protected Vector2 maxVelocity;         //Velocidade máxima nos eixos
        protected float walkSpeed;               //Velocidade de caminhada
        protected float jumpPower;               //Força do pulo
        protected bool animating;              //Diz se o objeto está sofrendo animação
        protected bool collidable;             //Diz se o objeto sofre ou não colisão
        public bool isAnimate;              //Diz se o objeto PODE sofrer animacao ou nao;
        protected bool isMoving;               //Diz se o objeto está se movendo
        protected bool canJump;                 // Diz se o objeto pode pular;
        protected bool isFalling;              //Diz se o objeto está caindo
        protected bool isJumping;              //Diz se o objeto está pulando
        protected string lastAction;           //Última ação do personagem
        protected bool isAffectedByGravity;    //Se o objeto é afetado pela gravidade
        protected float dy;                    //Variacao no eixo y

        protected bool visible;                //Diz se o sprite está visiível ou não
        protected bool facingRight;            //Diz para que direção o sprite está virado

        //Variáveis de animação
        protected Rectangle spriteImage;       //Posição da imagem na spritesheet
        protected float alpha;                           //Transparência da imagem
        protected Color spriteColor;           //Máscara de cor que será aplicada na imagem
        protected float rotation;              //Rotação da imagem
        protected float scale;                 //Scale da imagem
        protected Vector2 rotation_point;      //Ponto em que a imagem sofrerá rotação
        protected SpriteEffects effects;       //Realizar o flip da imagem (horizontal ou vertical)
        protected float depth;                 //Profundidade
        protected int currentFrame;
        protected List<Animation> animations;  //Lista de animações
        protected int currentAnimationIndex;   //Index da animação atual

        public bool Animating
        {
            get { return animating; }
            set { animating = value; }
        }//Animating

        public Vector2 Position
        {
            get { return position;  }
            set { position = value; }
        }//Position

        public Vector2 LastPosition
        {
            get { return lastPosition; }
            set { lastPosition = value; }
        }//LastPosition

        public Rectangle BoundingBox
        {
            get { return boundingBox;  }
            set { boundingBox = value; }
        }//BoundingBox

        public Vector2 ScreenLocation
        {
            get { return Camera.Transform(position); }
        }//ScreenLocation

       public Rectangle WorldRectangle
        {
            get
            {
                return new Rectangle( 
                            (int)position.X, (int)position.Y,
                            getAnimation().width, getAnimation().height);
            }
        }//WorldRectangle

       public Rectangle ScreenRectangle
       {
           get
           {
               return Camera.Transform(WorldRectangle);
           }
       }//ScreenRectangle

       public Vector2 RelativeCenter
       {
           get { return new Vector2(getAnimation().width / 2, getAnimation().height / 2); }
       }//RelativeCenter

       public Vector2 WorldCenter
       {
           get { return position + RelativeCenter; }
       }//WorldCenter

       public Vector2 ScreenCenter
       {
           get { return Camera.Transform(position + RelativeCenter); }
       }//ScreenCenter

       public bool IsMoving
       {
           get { return isMoving; }
           set { isMoving = value; }
       }//IsMoving

       public bool IsJumping
       {
           get { return isJumping; }
           set { isJumping = value; }
       }//IsJumping

       public bool IsFalling
       {
           get { return isFalling; }
           set { isFalling = value; }
       }//IsFalling

       public bool IsAffectedByGravity
       {
           get { return isAffectedByGravity; }
           set { isAffectedByGravity = value; }
       }//IsAffectedByGravity

        public Sprite(Texture2D texture, GameWindow Window)
        {
            this.texture = texture;
            this.Window = Window;

            this.visible = true;
            this.alpha = 1.0f;
            this.spriteColor = new Color(1.0f * alpha, 1.0f * alpha, 1.0f * alpha);
            this.rotation = 0f;
            this.rotation_point = Vector2.Zero;
            this.scale = 1.0f;
            this.depth = 0f;
            this.facingRight = true;

            this.isFalling = false;
            this.isMoving = false;

            this.animations = new List<Animation>();
        }//Sprite

        //Método abstrato para atualizar o objeto, implementar durante a herança.
        public abstract void Update(GameTime gameTime);

        //Seta o index da animação atual
        public void setAnimationIndex(int index)
        {
            this.currentAnimationIndex = index;
        }

        //Pega o index da animação atual
        public int getAnimationIndex()
        {
            return currentAnimationIndex;
        }

        //Pega a animação atual
        public Animation getAnimation()
        {
            return animations.ElementAt(currentAnimationIndex);
        }

        //Desenha o sprite sem animações
        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            if (!visible)
                return;

            spriteBatch.Draw(this.texture, this.position, Color.White);
        }

        //Desenha o sprite levando em conta a animação
        public void Draw(GameTime gameTime, SpriteBatch spriteBatch, Boolean animating)
        {
            if (!visible)
                return;

            Animation anim = this.getAnimation(); //Pega a animação atual
            if (!Game1.pause)
            {
                int current_frame = (int)(gameTime.TotalGameTime.TotalSeconds * anim.fps) % anim.frames; //Frame atual
                currentFrame = current_frame;
            }

            spriteImage = new Rectangle(currentFrame * anim.width, anim.Y, anim.width, anim.height); // Posição na spritesheete

            effects = ((facingRight) ? SpriteEffects.None : SpriteEffects.FlipHorizontally);  //Devemos espelhar a imagem?

            spriteBatch.Draw(texture, ScreenCenter, spriteImage, spriteColor, rotation, RelativeCenter, scale, effects, depth);
        }

    }
}
